import { Component, cls, type StyledProps } from '@knno/jsx';
import SVGMore from '@mdi/svg/svg/dots-horizontal.svg';
import SVGPrev from '../../svg/chevron-left.svg';
import SVGNext from '../../svg/chevron-right.svg';
import { isDescendant } from '../../tools/utils';
import { DATA } from '../symbol';
import { paginatorStyle } from './pager.css';

export type PagerProps = StyledProps<Pager> & {
	pages?: number;
	buttons?: number;
	active?: number;
	/**
	 * active page changed
	 */
	onActivePage?: (this: Pager, page: number) => void;
};

export class Pager extends Component<PagerProps> {
	private [DATA] = {
		act: 0,
		pages: 0,
		buttons: 9,
	};

	protected render(): Node {
		return (
			// biome-ignore lint/a11y/useKeyWithClickEvents: <>
			<div
				class={cls(this.props.class, paginatorStyle)}
				style={this.props.style}
				onClick={(event) => {
					const buttons = Array.from(this.el.children);
					const elem = buttons
						.filter((elem) => isDescendant([elem], event.target as HTMLElement))
						.at(0);
					if (elem) {
						if (!elem.classList.contains('disabled')) {
							const v = elem.getAttribute('page');
							if (v !== null) {
								const srcCount = buttons.length;
								let idx = buttons.indexOf(elem);
								this.setActive(Number(v));
								this.props.onActivePage?.call(this, Number(v));
								if (buttons.length > srcCount && idx > srcCount / 2) {
									idx++;
								}
								(buttons[Math.min(idx, buttons.length - 1)] as HTMLElement).focus();
							}
						}
					}
				}}
			></div>
		);
	}

	constructor(props: PagerProps) {
		super(props);
		this.setPages(props.pages ?? 1);
		this.setButtons(props.buttons ?? 9);
		this.setActive(props.active ?? 1);
	}

	private renderContent() {
		const arr: (Node | string)[] = [];
		if (this[DATA].pages === 1 || this[DATA].buttons <= 2) {
			arr.push(
				<button type="button" page={this[DATA].act} class="active">
					{`${this[DATA].act}`}
				</button>,
				' / ',
				<button type="button" page={this[DATA].pages}>
					{`${this[DATA].pages}`}
				</button>,
			);
		} else {
			let buttons = this[DATA].buttons - 2;
			let diff = 0;
			if (this[DATA].buttons % 2 === 0) {
				diff = 1;
				buttons -= 1;
			}
			const helf = (buttons - 1) / 2;
			let begin = Math.max(2, this[DATA].act - helf);
			const end = Math.min(begin + helf * 2 + diff, this[DATA].pages - 1);
			begin = Math.max(2, Math.min(end - (helf * 2 + diff), begin));
			arr.push(
				<button type="button" class={this[DATA].act === 1 ? 'active' : ''} page={1}>
					1
				</button>,
			);
			if (begin >= 3 && this[DATA].pages > this[DATA].buttons) {
				arr.push(<button type="button" class="svg more" page={begin - 1} innerHTML={SVGMore} />);
			}
			for (let i = begin; i <= end; i++) {
				arr.push(
					<button type="button" class={i === this[DATA].act ? 'active' : ''} page={i}>
						{i + ''}
					</button>,
				);
			}
			if (end <= this[DATA].pages - 2 && this[DATA].pages > this[DATA].buttons) {
				arr.push(<button type="button" class="svg more" page={end + 1} innerHTML={SVGMore} />);
			}
			if (this[DATA].pages > 1) {
				arr.push(
					<button
						type="button"
						class={this[DATA].act === this[DATA].pages ? 'active' : ''}
						page={this[DATA].pages}
					>
						{this[DATA].pages + ''}
					</button>,
				);
			}
		}

		this.el.replaceChildren(
			<button
				type="button"
				class={['svg', 'prev', this[DATA].act === 1 ? 'disabled' : '']}
				innerHTML={SVGPrev}
				page={this[DATA].act - 1}
			/>,
			...arr,
			<button
				type="button"
				class={['svg', 'next', this[DATA].act === this[DATA].pages ? 'disabled' : '']}
				innerHTML={SVGNext}
				page={this[DATA].act + 1}
			/>,
		);
	}

	get active(): number {
		return this[DATA].act;
	}
	setActive(value: number): this {
		this[DATA].act = Math.min(this.pages, Math.max(1, value));
		this.renderContent();
		return this;
	}

	get pages(): number {
		return this[DATA].pages;
	}
	setPages(value: number): this {
		this[DATA].pages = Math.max(1, value);
		this.setActive(this[DATA].act);
		return this;
	}

	get buttons(): number {
		return this[DATA].buttons;
	}
	setButtons(value: number): this {
		this[DATA].buttons = Math.max(1, value);
		this.renderContent();
		return this;
	}
}
